package com.piece.core.framework.util.time;

import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.string.StringUtil;
import org.apache.commons.lang3.time.DateFormatUtils;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * 日期工具类
 */
public class DateUtil {

    // 系统当前时区
    private static final ZoneId ZONE = ZoneId.systemDefault();

    public static final String FORMAT_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String FORMAT_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String FORMAT_YYYY_MM_DD_E = "yyyy/MM/dd";
    public static final String FORMAT_YYYY_MM_DD_HH_MM_SS_E = "yyyy/MM/dd HH:mm:ss";
    public static final String FORMAT_YYYY_MM_DD_HH_MM_SS_a = "yyyy-MM-dd HH:mm:ss a";
    public static final String FORMAT_YYYY_nian_MM_yue_MM_ri = "yyyy年MM月dd日";
    public static final String FORMAT_YYYY_nian_MM_yue_MM_ri_HH_MM_SS = "yyyy年MM月dd日 HH:mm:ss";
    public static final String TIME_ZONE_GMT8 = "GMT+8";

    private static final int YEAR = 365 * 24 * 60 * 60; // 年
    private static final int MONTH = 30 * 24 * 60 * 60; // 月
    private static final int DAY = 24 * 60 * 60;        // 天
    private static final int HOUR = 60 * 60;            // 小时
    private static final int MINUTE = 60;               // 分钟
    private static final int SECONDS = 1;               // 秒

    private static final String[] FORMAT_ARRAY = {
            DateUtil.FORMAT_YYYY_MM_DD,
            DateUtil.FORMAT_YYYY_MM_DD_E,
            DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS,
            DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS_E,
            DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS_a,
            DateUtil.FORMAT_YYYY_nian_MM_yue_MM_ri,
            DateUtil.FORMAT_YYYY_nian_MM_yue_MM_ri_HH_MM_SS
    };

    /**
     * 设置当前时间为当天的最初时间（即00时00分00秒）
     *
     * @param cal 日期
     * @return 日期
     */
    public static Calendar setStartDay(Calendar cal) {
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        return cal;
    }

    /**
     * 设置当前时间为当天的最后时间（即23时59分59秒）
     *
     * @param cal 日期
     * @return 日期
     */
    public static Calendar setEndDay(Calendar cal) {
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        return cal;
    }

    /**
     * 格式化日期,yyyy-MM-dd
     */
    public static String formatDate(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_YYYY_MM_DD);
        return sdf.format(date);
    }

    /**
     * 格式化日期
     *
     * @param date 日期
     * @param fmt  日期格式
     */
    public static String formatDate(Date date, String fmt) {
        SimpleDateFormat sdf = new SimpleDateFormat(fmt);
        return sdf.format(date);
    }

    /**
     * 格式化中文时钟时间,yyyy年MM月dd日 HH:mm:ss
     *
     * @param date 日期
     * @return
     */
    public static final String formatDataClockCn(Date date) {
        return formatDate(date, DateUtil.FORMAT_YYYY_nian_MM_yue_MM_ri_HH_MM_SS);
    }

    /**
     * 字符串转日期
     *
     * @param date
     * @return
     */
    public static Date getDate(String date) {
        if (StringUtil.isEmpty(date)) {
            return null;
        }
        SimpleDateFormat sdf;
        Date result = null;
        for (String str : DateUtil.FORMAT_ARRAY) {
            sdf = new SimpleDateFormat(str);
            try {
                result = sdf.parse(date);
                break;
            } catch (ParseException e) {
            }
        }
        return result;
    }

    /**
     * 获取指定格式当前时间
     *
     * @param date   日期
     * @param format 日期格式
     * @return
     */
    public static Date getDate(String date, String format) throws ParseException {
        if (StringUtil.isEmpty(date)) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.parse(date);
    }

    /**
     * 获取当前时间
     *
     * @return 返回格式 yyyy-MM-dd
     */
    public static String getDateNow() {
        return getDateNow(FORMAT_YYYY_MM_DD);
    }

    /**
     * 获取当前时间
     *
     * @param format 日期格式
     * @return
     */
    public static String getDateNow(String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        sdf.setLenient(false);
        return sdf.format(new Date());
    }

    /**
     * 将LocalDate转换成Date
     */
    public static Date getDate(LocalDate localDate) {
        Instant instant = localDate.atStartOfDay().atZone(ZONE).toInstant();
        return Date.from(instant);
    }

    /**
     * 将LocalDateTime转换成Date
     */
    public static Date getDate(LocalDateTime localDateTime) {
        Instant instant = localDateTime.atZone(ZONE).toInstant();
        return Date.from(instant);
    }

    /**
     * 将Date转换成LocalDate
     */
    public static LocalDate getLocalDate(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZONE);
        return localDateTime.toLocalDate();
    }

    /**
     * 将Date转换成LocalTime
     */
    public static LocalTime date2LocalTime(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZONE);
        return localDateTime.toLocalTime();
    }

    /**
     * 将Date转换成LocalDateTime
     */
    public static LocalDateTime getLocalDateTime(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZONE);
        return localDateTime;
    }

    /**
     * 获取Period（时间段）
     */
    public static Period localDateDiff(LocalDate localDateL, LocalDate localDateG) {
        return Period.between(localDateL, localDateG);
    }

    /**
     * 获取Duration（持续时间）
     */
    public static Duration localTimeDiff(LocalTime localDateL, LocalTime localDateG) {
        return Duration.between(localDateL, localDateG);
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 获取星期初始时间
     *
     * @return 返回格式 yyyy-MM-dd
     */
    public static String getFirstDayOfWeek() {
        return getFirstDayOfWeek(FORMAT_YYYY_MM_DD);
    }

    /**
     * 获取指定格式的星期初始时间
     *
     * @param pattern
     * @return
     */
    public static String getFirstDayOfWeek(String pattern) {
        Calendar calendar = getFirstDayOfWeek(Calendar.getInstance());
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取星期初始时间
     */
    public static Calendar getFirstDayOfWeek(Calendar calendar) {
        int mondayPlus;
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek == 0) {
            dayOfWeek = 7;
        }
        mondayPlus = 1 - dayOfWeek;
        calendar.add(Calendar.DATE, mondayPlus);
        return calendar;
    }

    /**
     * 获取星期结尾时间
     *
     * @return 返回格式 yyyy-MM-dd
     */
    public static String getLastDayOfWeek() {
        return getLastDayOfWeek(FORMAT_YYYY_MM_DD);
    }

    /**
     * 获取指定格式的星期结尾时间
     */
    public static String getLastDayOfWeek(String pattern) {
        Calendar calendar = getLastDayOfMonth(Calendar.getInstance());
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取星期结尾时间
     */
    public static Calendar getLastDayOfWeek(Calendar calendar) {
        int mondayPlus;
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek == 0) {
            dayOfWeek = 7;
        }
        mondayPlus = 7 - dayOfWeek;
        calendar.add(Calendar.DATE, mondayPlus);
        return calendar;
    }

    /**
     * 获取月初时间
     *
     * @return 返回格式 yyyy-MM-dd
     */
    public static String getFirstDayOfMonth() {
        return getFirstDayOfMonth(FORMAT_YYYY_MM_DD);
    }

    /**
     * 获取指定格式的月初时间
     *
     * @param pattern
     * @return
     */
    public static String getFirstDayOfMonth(String pattern) {
        Calendar calendar = getFirstDayOfMonth(Calendar.getInstance());
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取月初时间
     */
    public static Calendar getFirstDayOfMonth(Calendar calendar) {
        if (null == calendar) {
            calendar = Calendar.getInstance();
        }
        calendar.set(Calendar.DATE, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        return calendar;
    }

    /**
     * 获取月末时间
     *
     * @return 返回格式 yyyy-MM-dd
     */
    public static String getLastDayOfMonth() {
        return getLastDayOfMonth(FORMAT_YYYY_MM_DD);
    }

    /**
     * 获取指定格式的月末时间
     */
    public static String getLastDayOfMonth(String pattern) {
        Calendar calendar = getLastDayOfMonth(Calendar.getInstance());
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取月末时间
     */
    public static Calendar getLastDayOfMonth(Calendar calendar) {
        if (null == calendar) {
            calendar = Calendar.getInstance();
        }
        calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return calendar;
    }

    /**
     * 获取年初时间
     *
     * @return 返回格式 yyyy-MM-dd
     */
    public static String getFirstDayOfYear() {
        return getFirstDayOfYear(FORMAT_YYYY_MM_DD);
    }

    /**
     * 获取指定格式的年初时间
     *
     * @param pattern
     * @return
     */
    public static String getFirstDayOfYear(String pattern) {
        Calendar calendar = getFirstDayOfYear(Calendar.getInstance());
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取年初时间
     */
    public static Calendar getFirstDayOfYear(Calendar calendar) {
        if (null == calendar) {
            calendar = Calendar.getInstance();
        }
        calendar.set(Calendar.DAY_OF_YEAR, calendar.getActualMinimum(Calendar.DAY_OF_YEAR));
        return calendar;
    }

    /**
     * 获取年末时间
     *
     * @return 返回格式 yyyy-MM-dd
     */
    public static String getLastDayOfYear() {
        return getLastDayOfYear(FORMAT_YYYY_MM_DD);
    }

    /**
     * 获取指定格式的年末时间
     *
     * @param pattern
     * @return
     */
    public static String getLastDayOfYear(String pattern) {
        Calendar calendar = getLastDayOfYear(Calendar.getInstance());
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取年末时间
     *
     * @param calendar 为null代表查询当前时间
     * @return
     */
    public static Calendar getLastDayOfYear(Calendar calendar) {
        if (null == calendar) {
            calendar = Calendar.getInstance();
        }
        calendar.set(Calendar.DAY_OF_YEAR, calendar.getActualMaximum(Calendar.DAY_OF_YEAR));
        return calendar;
    }

    /**
     * 依据类型返回日期中的元素
     *
     * @param date  日期,null查询当前时间
     * @param field Calendar对应field
     * @return 指定元素值
     */
    public static int getDateItems(Date date, int field) {
        if (null == date) {
            date = new Date();
        }
        GregorianCalendar cl = new GregorianCalendar();
        cl.setTime(date);
        return cl.get(field);
    }

    /**
     * 返回当前年份
     */
    public static int getYear() {
        return getYear(new Date());
    }

    /**
     * 返回给定日期的具体年份
     */
    public static int getYear(Date date) {
        return getDateItems(date, Calendar.YEAR);
    }

    /**
     * 返回当前月份
     */
    public static int getMonth() {
        return getMonth(new Date());
    }

    /**
     * 返回给定日期的具体月份
     */
    public static int getMonth(Date date) {
        return getDateItems(date, Calendar.MONTH) + 1;
    }

    /**
     * 返回当前天数
     */
    public static int getDay() {
        return getDay(new Date());
    }

    /**
     * 返回给定日期为当月中具体天数
     */
    public static int getDay(Date date) {
        return getDateItems(date, Calendar.DAY_OF_MONTH);
    }

    /**
     * 返回当前星期数
     *
     * @return 1：星期一  2：星期二  3：星期三  4：星期四  5：星期五  6：星期六  7：星期日
     */
    public static int getWeekDay() {
        return getWeekDay(new Date());
    }

    /**
     * 返回给定日期星期数
     *
     * @param date 日期
     * @return 1：星期一  2：星期二  3：星期三  4：星期四  5：星期五  6：星期六  7：星期日
     */
    public static int getWeekDay(Date date) {
        int num = getDateItems(date, Calendar.DAY_OF_WEEK) - 1;
        return num == 0 ? 7 : num;
    }

    /**
     * 返回星期名称
     *
     * @param start   起始位置 1：星期一  2：星期二  3：星期三  4：星期四  5：星期五  6：星期六  7：星期日
     * @param length  个数
     * @return
     */
    public static String[] getWeekNameRange(int start, int length) {
        String[] allWeeks = new String[]{"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};
        List<String> weekNames = new ArrayList<>();

        if (length < 0) {
            start = start + length;
        }

        for (int i = 0; i < Math.abs(length); i++) {
            String name = null;
            if (start < 0) {
                name = allWeeks[start + 7];
            } else if (start > 7) {
                name = allWeeks[start - 8];
            } else {
                name = allWeeks[start];
            }
            weekNames.add(name);
            start++;
        }

        return weekNames.stream().toArray(String[]::new);
    }

    /**
     * 根据参数条件加减日期
     *
     * @param date   日期对象,null代表当前时间
     * @param amount 增减数量
     * @param field  指定是年、月、日
     * @return
     */
    public static Date calculateDate(Date date, int amount, int field) {
        if (null == date) {
            date = new Date();
        }
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(field, amount);
        return calendar.getTime();
    }

    /**
     * 根据日期向前或向后推算N年
     *
     * @param years 年份数 正整数或负整数
     * @return
     */
    public static Date addYear(int years) {
        return calculateDate(new Date(), years, Calendar.YEAR);
    }

    /**
     * 根据日期向前或向后推算N年
     *
     * @param date  日期
     * @param years 年份数 正整数或负整数
     * @return
     */
    public static Date addYear(Date date, int years) {
        return calculateDate(date, years, Calendar.YEAR);
    }

    /**
     * 根据日期向前或向后推算N个月
     *
     * @param months 月份数 正整数或负整数
     * @return 返回增加月份后的日期对象
     */
    public static final Date addMonth(int months) {
        return calculateDate(new Date(), months, Calendar.MONTH);
    }

    /**
     * 根据日期向前或向后推算N个月
     *
     * @param date   日期
     * @param months 月份数 正整数或负整数
     * @return 返回增加月份后的日期对象
     */
    public static final Date addMonth(Date date, int months) {
        return calculateDate(date, months, Calendar.MONTH);
    }

    /**
     * 根据日期向前或向后推算N个星期
     *
     * @param months 星期数 正整数或负整数
     * @return
     */
    public static final Date addWeek(int months) {
        return calculateDate(new Date(), months, Calendar.WEEK_OF_YEAR);
    }

    /**
     * 根据日期向前或向后推算N个星期
     *
     * @param date 日期
     * @param week 星期数 正整数或负整数
     * @return
     */
    public static final Date addWeek(Date date, int week) {
        return calculateDate(date, week, Calendar.WEEK_OF_YEAR);
    }

    /**
     * 根据日期向前或向后推算N个日
     *
     * @param days 日天数，正整数或负整数
     * @return 返回增加天数后的日期对象
     */
    public static final Date addDay(int days) {
        return calculateDate(new Date(), days, Calendar.DAY_OF_MONTH);
    }

    /**
     * 根据日期向前或向后推算N个日
     *
     * @param date 日期
     * @param days 日天数，正整数或负整数
     * @return 返回增加天数后的日期对象
     */
    public static final Date addDay(Date date, int days) {
        return calculateDate(date, days, Calendar.DAY_OF_MONTH);
    }

    /**
     * 根据日期向前或向后推算N个小时
     */
    public static Date addHour(int hour) {
        return calculateDate(new Date(), hour, Calendar.HOUR_OF_DAY);
    }

    /**
     * 根据日期向前或向后推算N个小时
     */
    public static Date addHour(Date date, int hour) {
        return calculateDate(date, hour, Calendar.HOUR_OF_DAY);
    }

    /**
     * 计算两个时间差，以月为单位
     *
     * @param dDate1 起始日期
     * @param dDate2 结束日期
     * @return 月
     */
    public static long monthDiff(Date dDate1, Date dDate2) {
        long year, month;
        GregorianCalendar cld = new GregorianCalendar();
        cld.setTime(dDate2);
        year = cld.get(Calendar.YEAR);
        month = cld.get(Calendar.MONTH);
        cld.setTime(dDate1);
        year -= cld.get(Calendar.YEAR);
        month -= cld.get(Calendar.MONTH);
        return year * 12 + month;
    }

    /**
     * 计算两个时间差，以天为单位
     *
     * @param dDate1 起始日期
     * @param dDate2 结束日期
     * @return 天
     */
    public static int dayDiff(Date dDate1, Date dDate2) {
        long nd = 1000 * 24 * 60 * 60;
        long diff = dDate2.getTime() - dDate1.getTime();
        return (int) (diff / nd);
    }

    /**
     * 计算两个时间差，以小时为单位
     *
     * @param dDate1 起始日期
     * @param dDate2 结束日期
     * @return 小时
     */
    public static long hourDiff(Date dDate1, Date dDate2) {
        long nh = 1000 * 60 * 60;
        long diff = dDate2.getTime() - dDate1.getTime();
        return diff / nh;
    }

    /**
     * 计算两个时间差，以分钟为单位
     *
     * @param dDate1 起始日期
     * @param dDate2 结束日期
     * @return 小时
     */
    public static long minuteDiff(Date dDate1, Date dDate2) {
        long nm = 1000 * 60;
        long diff = dDate2.getTime() - dDate1.getTime();
        return diff / nm;
    }

    /**
     * 计算两个时间差，以秒为单位
     *
     * @param dDate1 起始日期
     * @param dDate2 结束日期
     * @return 秒
     */
    public static Long secondDiff(Date dDate1, Date dDate2) {
        long nm = 1000 * 60;
        long diff = dDate1.getTime() - dDate2.getTime();
        return diff / nm;
    }

    /**
     * 计算两个时间差
     *
     * @return day 天 hour 小时 min 分钟"
     */
    public static String diff(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 判断当前时间是否在指定日期之间
     *
     * @param dDate1 起始日期
     * @param dDate2 结束日期
     * @return
     */
    public static boolean isBetweenDate(Date dDate1, Date dDate2) {
        long date_1 = dDate1.getTime();
        long date_2 = dDate2.getTime();
        long date = new Date().getTime();
        return date > date_1 && date < date_2;
    }

    /**
     * 得到上月的第一天
     */
    public static Date getLastMonthFirstDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        return calendar.getTime();
    }

    /**
     * 得到上月的最后一天
     */
    public static Date getLastMonthLastDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return calendar.getTime();
    }

    /**
     * 判断日期是否为年初第一天
     */
    public static boolean isFirstDayOfYear(Date date) {
        return (getMonth(date) == 1) && (getDay(date) == 1);
    }

    /**
     * 判断是否闰年
     */
    public static boolean isLeapYear(int year) {
        return new GregorianCalendar().isLeapYear(year);
    }

    /**
     * 返回给定日期当年天数
     */
    public static int getYearDays(Date date) {
        return isLeapYear(getYear(date)) ? 366 : 365;
    }

    /**
     * 返回指定日期区间段内瑞年个数
     */
    public static int getLeapYears(Date sDate, Date eDate) throws ParseException {
        int leap = 0;
        Date dDate = null;
        for (int i = getYear(sDate); i <= getYear(eDate); i++) {
            if (isLeapYear(i)) {
                dDate = getDate(i + "-02-29", FORMAT_YYYY_MM_DD);
                if (dayDiff(dDate, sDate) <= 0 && dayDiff(dDate, eDate) >= 0) {
                    leap++;
                }
            }
        }
        return leap;
    }

    /**
     * 字符串类型的日期转换为Date类型
     *
     * @param date
     */
    @Deprecated
    public static Date toDate(String date) {
        // 是否有分隔符判断标识
        Boolean re = false;
        char ss, cc;
        String[] sss = {"-", "/", "."};
        String[] result;
        int jj, kk, mm;
        GregorianCalendar calendar = null;
        int d_len = date.length();
        // 检查分隔符
        for (jj = 0; jj < sss.length; jj++) {
            if (date.indexOf(sss[jj]) >= 0) {
                // 有分隔符时置为true
                re = true;
                break;
            }
        }
        if (re) {
            //有分隔符的
            if (jj >= sss.length) {
                //格式错误
                return null;
            }
            ss = sss[jj].charAt(0);
            // 检查数字有效性即除了数字和分隔符，不应该再包括其它字符
            for (int i = 0; i < d_len; i++) {
                cc = date.charAt(i);
                if (cc != ss && (cc < '0' || cc > '9')) {
                    //格式错误
                    return null;
                }
            }
            //检查全部，包括空的元素，用0会忽略空
            result = date.split(sss[jj], -1);
            if (result.length != 3) {
                //格式错误
                return null;
            }
            jj = Integer.parseInt(result[0]);
            kk = Integer.parseInt(result[1]);
            mm = Integer.parseInt(result[2]);

            //判断是否符合一种日期格式
            if (isValidDate(jj, kk, mm)) {
                //1、y/M/d格式
                calendar = new GregorianCalendar(jj < 30 ? jj + 2000 :
                        (jj <= 99 ? jj + 1900 : jj), kk - 1, mm);
            } else {
                if (mm < 30)
                    mm += 2000;
                else if (mm <= 99)
                    mm += 1900;
                if (isValidDate(mm, jj, kk)) {
                    //2、M/d/y格式
                    calendar = new GregorianCalendar(mm, jj - 1, kk);
                } else if (isValidDate(mm, kk, jj)) {
                    //3、d/M/y格式
                    calendar = new GregorianCalendar(mm, kk - 1, jj);
                } else {
                    //格式错误
                    return null;
                }
            }
        } else {
            //无分隔符的
            if (d_len != 8) {
                //无分隔符的日期不等于八位则为非法日期格式
                //格式错误
                return null;
            }
            //检查数字有效性即除了数字，不应该再包括其它字符
            for (int i = 0; i < d_len; i++) {
                cc = date.charAt(i);
                if (cc < '0' || cc > '9') {
                    //格式错误
                    return null;
                }
            }
            jj = Integer.parseInt(date.substring(0, 4));
            kk = Integer.parseInt(date.substring(4, 6));
            mm = Integer.parseInt(date.substring(6, 8));
            if (isValidDate(jj, kk, mm)) {
                calendar = new GregorianCalendar(jj < 30 ? jj + 2000 :
                        (jj <= 99 ? jj + 1900 : jj), kk - 1, mm);
            } else {
                //格式错误
                return null;
            }
        }
        return calendar.getTime();
    }

    /**
     * 判断年月日是否在正常范围
     *
     * @param year  正常范围在0-99和1000－9999
     * @param month 正常范围在0-12
     * @param day
     * @return
     */
    private static boolean isValidDate(int year, int month, int day) {
        GregorianCalendar calendar;
        if (year < 0 || (year > 99 && (year < 1000 || year > 9999))) {
            return false;
        }
        if (year < 30) {
            year += 2000;
        } else if (year <= 99) {
            year += 1900;
        }
        if (month < 1 || month > 12) {
            return false;
        }
        calendar = new GregorianCalendar(year, month - 1, 1); //参数月份从0开始所以减一
        return day >= calendar.getActualMinimum(Calendar.DAY_OF_MONTH) &&
                day <= calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 获取日期所在季度
     *
     * @param date
     * @return 1:第一季度,2:第二季度,3:第三季度,4:第四季度
     */
    public static int getQuarterDay(Date date) {
        if (null == date) {
            date = new Date();
        }
        int m = getMonth(date);
        // 季度
        return (int) Math.ceil((m - 1) / 3) + 1;
    }

    /**
     * 获取当季第一天,yyyy-MM-dd
     */
    public static Date getQuarterFirstDay(Date date) throws ParseException {
        Date quarterDay = null;
        int s = getQuarterDay(date);
        String year = String.valueOf(getYear(date));
        switch (s) {
            case 1:
                quarterDay = getDate(year + "-01-01", FORMAT_YYYY_MM_DD);
                break;
            case 2:
                quarterDay = getDate(year + "-04-01", FORMAT_YYYY_MM_DD);
                break;
            case 3:
                quarterDay = getDate(year + "-07-01", FORMAT_YYYY_MM_DD);
                break;
            case 4:
                quarterDay = getDate(year + "-10-01", FORMAT_YYYY_MM_DD);
                break;
        }
        return quarterDay;
    }

    /**
     * 获取当季最后一天,yyyy-MM-dd
     */
    public static Date getQuarterLastDay(Date date) throws ParseException {
        Date quarterDay = null;
        int s = getQuarterDay(date);
        String year = String.valueOf(getYear(date));
        switch (s) {
            case 1:
                quarterDay = getDate(year + "-03-31", FORMAT_YYYY_MM_DD);
                break;
            case 2:
                quarterDay = getDate(year + "-06-30", FORMAT_YYYY_MM_DD);
                break;
            case 3:
                quarterDay = getDate(year + "-09-30", FORMAT_YYYY_MM_DD);
                break;
            case 4:
                quarterDay = getDate(year + "-12-31", FORMAT_YYYY_MM_DD);
                break;
        }
        return quarterDay;
    }

    /**
     * 获取年份列表
     *
     * @return 当前年份前200年到后200年
     */
    public static List<String> getAllYear() {
        return getAllYear(getYear(), 200);
    }

    /**
     * 获取年份列表
     *
     * @param year  当前年份
     * @param count 总共年份数
     */
    public static List<String> getAllYear(int year, int count) {
        List<String> list = new ArrayList<>();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy");
        Calendar now = Calendar.getInstance();
        int length = count * 2;
        for (int i = 0; i < length; i++) {
            now.set(Calendar.YEAR, year - count + i);
            list.add(formatter.format(now.getTime()));
        }
        return list;
    }

    /**
     * 查询月份记录
     */
    public static List<String> getAllMonthTwoBit() {
        List<String> plist = new ArrayList<>();
        for (int i = 1; i <= 12; i++) {
            plist.add(StringUtil.getBitVersion(i + "", 2));
        }
        return plist;
    }

    /**
     * 查询日期记录
     *
     * @param month 月份
     */
    public static List<String> getAllDay(int month) {
        List<String> list = new ArrayList<>();
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.set(Calendar.MONTH, month - 1);
        int start = calendar.getActualMinimum(Calendar.DAY_OF_MONTH);
        int end = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int i = start; i <= end; i++) {
            list.add(StringUtil.getBitVersion(i + "", 2));
        }
        return list;
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 根据执行时间长度获取描述性时间
     *
     * @param execTime 执行时间 单位为毫秒
     * @return 时间字符串
     */
    public static String getDescriptionTime(long execTime) {
        if (execTime < 1000) {
            return execTime + "毫秒";
        }

        long timeGap = execTime / 1000;
        long msGap = execTime % 1000;
        StringBuffer timeBuffer = new StringBuffer();
        String temp[] = null;
        do {
            temp = convertTimeDescription(timeGap);
            if (null != temp) {
                timeBuffer.append(temp[0]);
                timeGap = Convert.toLong(temp[1]);
            }
        } while (null != temp);

        if (msGap != 0) {
            timeBuffer.append(msGap + "毫秒");
        }

        return timeBuffer.toString();
    }

    /**
     * 根据时间戳获取描述性时间，如3分钟前，1天前
     *
     * @param timestamp 时间戳 单位为毫秒
     * @return 时间字符串
     */
    public static String getDescriptionTimeFromTimestamp(long timestamp) {
        long currentTime = new Date().getTime();
        long timeGap = (currentTime - timestamp) / 1000;
        String[] timeStr = convertTimeDescription(timeGap);
        if (null == timeStr || timeStr[0].indexOf("秒") > -1) {
            return "刚刚";
        } else {
            return timeStr[0] + "前";
        }
    }

    /**
     * 根据时间戳获取两位描述性时间
     *
     * @param time 时间戳 单位为毫秒
     */
    public static String[] convertTimeDescription(long time) {
        String timeStr[] = new String[2];
        if (time > YEAR) {
            timeStr[0] = time / YEAR + "年";
            timeStr[1] = Convert.toStr(time % YEAR, "0");
        } else if (time > MONTH) {
            timeStr[0] = time / MONTH + "月";
            timeStr[1] = Convert.toStr(time % MONTH, "0");
        } else if (time > DAY) {
            timeStr[0] = time / DAY + "天";
            timeStr[1] = Convert.toStr(time % DAY, "0");
        } else if (time > HOUR) {
            timeStr[0] = time / HOUR + "小时";
            timeStr[1] = Convert.toStr(time % HOUR, "0");
        } else if (time > MINUTE) {
            timeStr[0] = time / MINUTE + "分钟";
            timeStr[1] = Convert.toStr(time % MINUTE, "0");
        } else if (time > SECONDS) {
            timeStr[0] = time / SECONDS + "秒";
            timeStr[1] = Convert.toStr(time % SECONDS, "0");
        } else {
            return null;
        }
        return timeStr;
    }

    /**
     * 获取上月的第一天
     */
    public static LocalDate getFirstDayOfLastMonth(LocalDate date) {
        return date.with((temporal) -> temporal.with(ChronoField.DAY_OF_MONTH, 1).plus(-1, ChronoUnit.MONTHS));
    }

    /**
     * 获取上月的最后一天
     */
    public static LocalDate getLastDayOfLastMonth(LocalDate date) {
        return date.with((temporal) -> temporal.plus(-1, ChronoUnit.MONTHS).with(ChronoField.DAY_OF_MONTH,
                temporal.range(ChronoField.DAY_OF_MONTH).getMaximum()));
    }

    /**
     * 获取当月的第一天
     */
    public static LocalDate getFirstDayOfMonth(LocalDate date) {
        return date.with((temporal) -> temporal.with(ChronoField.DAY_OF_MONTH, 1));
    }

    /**
     * 获取当月的最后一天
     */
    public static LocalDate getLastDayOfMonth(LocalDate date) {
        return date.with((temporal) -> temporal.with(ChronoField.DAY_OF_MONTH,
                temporal.range(ChronoField.DAY_OF_MONTH).getMaximum()));
    }

    /**
     * 获取下月的第一天
     */
    public static LocalDate getFirstDayOfNextMonth(LocalDate date) {
        return date.with((temporal) -> temporal.plus(1, ChronoUnit.MONTHS).with(ChronoField.DAY_OF_MONTH, 1));
    }

    /**
     * 获取下月的最后一天
     */
    public static LocalDate getLastDayOfNextMonth(LocalDate date) {
        return date.with((temporal) -> temporal.plus(1, ChronoUnit.MONTHS).with(ChronoField.DAY_OF_MONTH,
                temporal.range(ChronoField.DAY_OF_MONTH).getMaximum()));
    }

    /**
     * 获取上一年的第一天
     */
    public static LocalDate getFirstDayOfLastYear(LocalDate date) {
        return date.with((temporal) -> temporal.with(ChronoField.DAY_OF_YEAR, 1).plus(-1, ChronoUnit.YEARS));
    }

    /**
     * 获取上一年的最后一天
     */
    public static LocalDate getLastDayOfLastYear(LocalDate date) {
        return date.with(
                (temporal) -> temporal.with(ChronoField.DAY_OF_YEAR, temporal.range(ChronoField.DAY_OF_YEAR).getMaximum())
                        .plus(-1, ChronoUnit.YEARS));
    }

    /**
     * 获取当年的第一天
     */
    public static LocalDate getFirstDayOfYear(LocalDate date) {
        return date.with((temporal) -> temporal.with(ChronoField.DAY_OF_YEAR, 1));
    }

    /**
     * 获取当年的最后一天
     */
    public static LocalDate getLastDayOfYear(LocalDate date) {
        return date.with(
                (temporal) -> temporal.with(ChronoField.DAY_OF_YEAR, temporal.range(ChronoField.DAY_OF_YEAR).getMaximum()));
    }

    /**
     * 获取下一年的第一天
     */
    public static LocalDate getFirstDayOfNextYear(LocalDate date) {
        return date.with((temporal) -> temporal.with(ChronoField.DAY_OF_YEAR, 1).plus(1, ChronoUnit.YEARS));
    }

    /**
     * 获取下一年的最后一天
     */
    public static LocalDate getLastDayOfNextYear(LocalDate date) {
        return date.with(
                (temporal) -> temporal.with(ChronoField.DAY_OF_YEAR, temporal.range(ChronoField.DAY_OF_YEAR).getMaximum())
                        .plus(1, ChronoUnit.YEARS));
    }

    /**
     * 得到几秒之前的时间
     */
    public static Date getSecondBefore(Date date, int second) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.add(Calendar.SECOND, second * -1);
        return now.getTime();
    }

    /**
     * 得到几秒之后的时间
     */
    public static Date getSecondAfter(Date date, int second) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.add(Calendar.SECOND, second);
        return now.getTime();
    }

    /**
     * 得到几分之前的时间
     */
    public static Date getMinuteBefore(Date date, int minute) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.add(Calendar.MINUTE, minute * -1);
        return now.getTime();
    }

    /**
     * 得到几分之后的时间
     */
    public static Date getMinuteAfter(Date date, int minute) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.add(Calendar.MINUTE, minute);
        return now.getTime();
    }

    /**
     * 得到某天的几小时前的时间 （24小时制）
     */
    public static Date getHourBefore(Date date, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY) - day);
        return now.getTime();
    }

    /**
     * 得到某天的几小时后的时间 （24小时制）
     */
    public static Date getHourAfter(Date date, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.HOUR_OF_DAY, now.get(Calendar.HOUR_OF_DAY) + day);
        return now.getTime();
    }

    /**
     * 得到某天的几个星期前的时间
     */
    public static Date getWeekBefore(Date date, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.WEEK_OF_YEAR, now.get(Calendar.WEEK_OF_YEAR) - day);
        return now.getTime();
    }

    /**
     * 得到某天的几个星期后的时间
     */
    public static Date getWeekAfter(Date date, int day) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.WEEK_OF_YEAR, now.get(Calendar.WEEK_OF_YEAR) + day);
        return now.getTime();
    }

    /**
     * 取指定日期的指定月数后的日期
     */
    public static Date getMonthBefore(Date date, int months) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.MONTH, now.get(Calendar.MONTH) - months);
        return now.getTime();
    }

    /**
     * 取指定日期的指定月数后的日期
     */
    public static Date getMonthAfter(Date date, int months) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.MONTH, now.get(Calendar.MONTH) + months);
        return now.getTime();
    }

    /**
     * 得到某天的几年前的时间
     */
    public static Date getYearBefore(Date date, int year) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.YEAR, now.get(Calendar.YEAR) - year);
        return now.getTime();
    }

    /**
     * 得到某天的几年后的时间
     */
    public static Date getYearAfter(Date date, int year) {
        Calendar now = Calendar.getInstance();
        now.setTime(date);
        now.set(Calendar.YEAR, now.get(Calendar.YEAR) + year);
        return now.getTime();
    }

    /**
     * 获得两个时间差，秒
     */
    public static Long getDateDifference(Date d1, Date d2) {
        try {
            long diff = d1.getTime() - d2.getTime();
            long days = diff / (1000 * 60);
            return days;
        } catch (Exception e) {
            return null;
        }
    }

    public static int getSysYear() {
        Calendar calendar = new GregorianCalendar();
        int iyear = calendar.get(Calendar.YEAR);
        return iyear;
    }

    public static int getSysMonth() {
        Calendar calendar = new GregorianCalendar();
        int imonth = calendar.get(Calendar.MONTH) + 1;
        return imonth;
    }

    public static int getSysDay() {
        Calendar calendar = new GregorianCalendar();
        int idate = calendar.get(Calendar.DAY_OF_MONTH);
        return idate;
    }

    /**
     * 比较两个时间
     * @return 大于：1 等于：0 小于：-1
     */
    public static int compareTo(Date date, Date anotherDate) {
        long thisTime = date.getTime();
        long anotherTime = anotherDate.getTime();
        return (thisTime < anotherTime ? -1 : (thisTime == anotherTime ? 0 : 1));
    }

    public static boolean isBeforeNow(Date date) {
        return date.getTime() < System.currentTimeMillis();
    }

    public static boolean isAfterNow(Date date) {
        return !isBeforeNow(date);
    }
}
